﻿using EFCore.EntityFrameworkExtensions;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;


namespace System.Linq
{
    /// <summary>
    /// 表达式扩展
    /// </summary>
    /// <typeparam name="T">泛型</typeparam>
    public static class IQueryableExtension
    {
        /// <summary>
        /// 表达式动态拼接查询
        /// </summary>
        public static IQueryable<TSource> Where<TSource>(this IQueryable<TSource> source, IList<QueryEntity> entities)
        {
            if (entities.Count == 0)
            {
                return source;
            }
            ParameterExpression param = Expression.Parameter(typeof(TSource));
            var expression = QueryExpression.CreateExpressionDelegate(param, entities);
            var lambda_expression = Expression.Lambda<Func<TSource, bool>>(expression, param);
            return source.Where(lambda_expression);
        }

        /// <summary>
        /// 字符串形式排序 
        /// </summary>
        public static IOrderedQueryable<TSource> OrderBy<TSource>(this IQueryable<TSource> source, string orderBy)
        {
            if (string.IsNullOrWhiteSpace(orderBy))
            {
                throw new ArgumentNullException();
            }
            var type = typeof(TSource);
            var parameter = Expression.Parameter(type);
            var orderbys = orderBy.Split(',');
            for (var i = 0; i < orderbys.Length; i++)
            {
                var orderby = orderbys[i];
                var ts = orderby.Split(' ', StringSplitOptions.RemoveEmptyEntries);
                var filed = ts[0];
                string sort = null;
                if (ts.Length > 1 && ts[1].ToLower() == "desc")
                {
                    sort = i == 0 ? "OrderByDescending" : "ThenByDescending";
                }
                else
                {
                    sort = i == 0 ? "OrderBy" : "ThenBy";
                }
                var fs = filed.Split('.');                
                Expression propertyAccess = parameter;
                for (var j = 0; j < fs.Length; j++)
                {
                    propertyAccess = Expression.Property(propertyAccess, fs[j]);
                }              
                var orderByExp = Expression.Lambda(propertyAccess, parameter);
                var types = new Type[] { type, propertyAccess.Type };
                MethodCallExpression resultExp = Expression.Call(typeof(Queryable),sort, types,  source.Expression, Expression.Quote(orderByExp));
                source = source.Provider.CreateQuery<TSource>(resultExp);
            }
            return source as IOrderedQueryable<TSource>;
        }
    }
}
